This page last changed on Apr 11, 2009 by aunger.

OTrunk Developers FAQ

How to...

Hiding left side view in OTViewer

Q. The OTViewer always displays that left side panel with a tree view, but I don't want to show it. How do I take it out?
A. There are a few ways to do that. If you just want to temporarily take it out when you are running your application from Eclipse, you can set the otrunk.view.hide_tree property to true on the Eclipse launcher. For more information, look at OTrunk Viewer Properties.
If you want to get rid of the left panel altogether, you can set that in your otml file. There is a property for that on the OTViewBundle object (the one that contains all your view entries). Just set it to false, like this:

<OTViewBundle showLeftPanel="false" ...
For more information on how to make your own otml file, look at Creating otml files.

Creating new OT objects from code

Q. I need to create a new OT object (instance) from scratch from my code. The keyword new doesn't seem to work (specially when the ot object is just an interface). How do I do that?
A. Use OTObjectService to create a new ot object, using the method createObject() and passing the class you need. OTObjectService also provides other services like making copies of ot objects. In order to get an instance of OTObjectService, you can use an existing OTObject an then call the getOTObjectService() method on it. If you are a writing a script, you can use the variable "otObjectService" directly from your code.

Listening to OT changes

Q. How do I add an OTChangeListener to an OTObject
A. You can add change listeners OTChangeNotifying objects. Most OTObjects implement OTChangeNotifying. If they do not, ask their author why and if they can fix it.

Getting real objects

Q. How do I get a "real object" out of an OT object?
A. You need an instance of OTControllerService (see next question). Then you can call the method getRealObject() on it.

Getting a controller service

Q. How do I get an OTControllerService object?
A. There are multiple ways:

  • If you are in a script, you can just use the variable "controllerService".
  • If you are a in a OTJComponentView and you are extending from AbstractOTJComponentView, then you can use the method createControllerService() to obtain an instance of a controller service that will work with your view context.
  • If you are in an OTView that extends AbstractOTView, you can use this snippet of code:
    	OTControllerServiceFactory controllerServiceFactory = 
    			(OTControllerServiceFactory) getViewService(OTControllerServiceFactory.class);
    		
        	OTControllerService controllerService = controllerServiceFactory.createControllerService();
    	
        	return controllerService;
    
  • If you are in an OTView that doesn't extend AbstractOTView, you should extends OTViewContextAware and use this snippet of code:
    	public void setViewContext(OTViewContext viewContext)
    	{
    		this.viewContext = viewContext;
    	}
    
            ...
    	OTControllerServiceFactory controllerServiceFactory = 
    			(OTControllerServiceFactory) viewContext.getViewService(OTControllerServiceFactory.class);
    		
        	OTControllerService controllerService = controllerServiceFactory.createControllerService();
    
  • If you are in an OTController and you are extending DefaultOTController, you can use the protected field "controllerService", which is set in the initialize method.
  • If you are not in an OTView or an OTController you can use an instance of OTObjectService and then call the method createControllerService() on it. You can obtain an OTObjectService object out of your OTObject, calling the method getOTObjectService(). This approach should be used as a last option.

Sharing a real objects between views

Q. I want to share a single real object between 2 views how can I do this?
A. The OTController which is responsible for that real object needs to return *true" for the
isRealObjectSharable(OTObject otObject, Object realObject) method. If it does so and both views have a common top level container, then the real object will be shared. The current top level containers are: OTViewer, OTUDLSidebarView, new frames created by the OTFrameManager

OT object IDs

Q. When I reference an ot object, I do <object refid="${local_id}"/>. What is that dollar sign for?
A. The dollar sign and the curly brackets mean that the ID is a local id. If you are using a global id, you don't put the $ or the {}.

OT object IDs - Refer to an object by a local_id instead of its existing global id

Q. I want to reference an object or view by a local_id, but it already has/needs to have a global id. Can I do that?
A. Yes, you can use an idMap, which maps global ids to local_ids. At the same level as the <imports> in the otml file, add

<idMap>
  <idMapping local_id="my-id-1" id="23cc14f0-c44f-11dc-95ff-0800200c9a66"/>
  <idMapping local_id="my-id-2" id="31193bb0-c44f-11dc-95ff-0800200c9a66"/>
</idMap>

Now wherever you would use <object refid="23cc14f0-c44f-11dc-95ff-0800200c9a66"/> you can use <object refid="${my-id-1}"/>

Getting views from OT objects

Q. I have an ot object, but I need an instance of its view. How do I get that?
A. You need a JComponentViewContext object, and this context has to be in the same context as the view you want to get.
If you are a view and you are extending AbstractOTJComponentView, then you can use this snippet of code:

getJComponentService().getJComponentViewContext().getViewByObject(otObject);

If you are in a script, you need to give access to the view to the OTScriptObject in the otml file. To do that, add an OTScriptVariableView entry to the variables section of the OTScriptObject. Then, you can use the view as a normal variable from your script.

Writing otml files - Using maps

Q. I want to use a map but I don't know how to write the otml for that.
An OTObjectMap allows you to have a table with strings as keys and OTObjects as values. This is a sample code. Say there is a class called OTExample with an OTObjectMap property called mapProperty. Then the otml would look something like this:

<OTExample>
  <mapProperty>
    <entry key="key1">
      <OTExampleObject/>
    </entry>
    <entry key="key2">
      <OTExampleObject/>
    </entry>
  </mapProperty>
</OTExample>

An OTResourceMap allows you to have a table with strings as keys and primitives as values. This is a sample code. Say there is a class called OTExample with an OTResourceMap property called mapProperty. Then the otml would look something like this:

<OTExample>
  <mapProperty>
    <entry key="key1">
      <boolean>true</boolean>
    </entry>
    <entry key="key2">
      <int>2</int>
    </entry>
  </mapProperty>
</OTExample>

Writing otml files - Including external otml files

Q. I want to reference an object that is defined on a separate otml file that the one I'm writing. Can I do that?
A. Yes, you can include the external otml file using an OTInclude object in the includes subsection of the OTSystem section on your otml file. Then you can reference the object normally, using its global id.

<includes>
  <OTInclude href="my_external_file.otml"/>
</includes>

Writing otml files - Directly use the root object from an external otml file

Q. I want to directly reference an external without having to first import it and then refer to the id of the object. Can I do that?
A. Yes, there is a short-cut to the above how-to which directly references the root object of an external otml file.

Use:

<OTIncludeRootObject href="/path/to/otml/file.otml"/>

where you would use

<object refid="${some-external-object}"/>

with the viewClass org.concord.otrunk.OTIncludeRootObjectView

Viewing and editing learner data directly

Q. I want to edit a student's otml data by hand and post it to the SDS as a new bundle.
A. First you need to find the student's data in the SDS. To do this, you must navigate to the SDS offering associated with a specific activity offered by a DIY. e.g. http://saildataservice.concord.org/13/offering/7086. Then you copy the url referenced by the Run link next to the student's name, e.g. http://saildataservice.concord.org/13/offering/7086/jnlp/19407. Then you append the session property "sailotrunk.learnerotml.edit=true" to that url:

http://saildataservice.concord.org/13/offering/7086/jnlp/19407?sailotrunk.learnerotml.edit=true

This will launch the SailOTViewer and show you a text representation of the learner's otml. You can then edit this otml by hand, and upload it as a new bundle by closing the window (you will be asked to confirm upload). Note that no xml checking is done at this point, so there are no guarantees on what will happen if the xml is invalid.

Get all loaded objects of a certain type

Q. I want to find all loaded OTObjects that match a given Class
A. OTrunkImpl has a helper method which will return an ArrayList of OTObjects which match the class (or a sub-class) of the type you pass in.

Example:

/* Assume we have an OTObject and an OTrunkImpl object
 * OTObject otObj = ...
 * OTrunkImpl otrunk = ...
 */

// get all objects using the default root object service
ArrayList<OTObject> objects = otrunk.getAllObjects(OTMultiUser.class);

// get all objects, using a specific object service to resolve the objects
ArrayList<OTObject> otherObjects = otrunk.getAllObjects(OTDocument.class, otObj.getObjectService());

Get objects which reference another object, indirectly or directly

Q. I want to find all objects that reference an object directly, or all objects which reference an object indirectly
A. OTrunkImpl has some helper methods which will return a list of OTIDs to objects that reference the passed in object

Examples:

/* Assume we have an OTObject and an OTrunkImpl object
 * OTObject otObj = ...
 * OTObject ignoreObject = ...
 * OTrunkImpl otrunk = ...
 */
//public ArrayList<OTID> getReferences(OTID objectID, Class<?> filterClass, boolean recurse, ArrayList<OTID> excludeIDs)

// filterClass will filter the collection of references by a certain class, similar to OTrunkImpl.getAllObjects(Class) does (can be null)
// recursion sets whether to find indirect references (true), or only direct references (false)
// excludeIDs is a list of OTIDs which we don't want to include and don't want to recurse through (can be null)

ArrayList<OTID> directReferences = otrunk.getReferences(otObj.getGlobalId(), null, false, null);
ArrayList<OTID> allReferences = otrunk.getReferences(otObj.getGlobalId(), null, true, null);
ArrayList<OTID> allDocumentReferences = otrunk.getReferences(otObj.getGlobalId(), OTDocument.class, true, null);
ArrayList<OTID> allReferencesExceptSome = otrunk.getReferences(otObj.getGlobalId(), null, true, ignoreObject.getGlobalId());

Common error messages and solutions

Errors when loading an otml file

Q. I'm getting an error that says can't find handler for: .... What does that mean?
A. It means that it cannot find the class you are referring to. If it is an OTObject, you need to add it to the imports section of your otml file.

Errors when loading an otml file

Q. I'm importing a class in the imports section, but I'm still getting an error that says Error importing class: ... this class was listed as an import in the otml file. I checked the spelling of the package and the class and looks right. What's wrong?
A. All the classes that you put in the imports section have to be OTObject. If the class you want to import is indeed an OTObject, then this error probably means that the class needed is not in the classpath. The solution depends how are you running the otml file. If you are using a launcher from Eclipse, you just have to add the appropriate project or jar file to the launcher. If you are launching from otrunk-examples, make sure the build system has the latest jar files and that the project has the correct dependencies.
If the class you are trying to import is not an OTObject, then you don't need to import it. For example, if it's an OTView, you should not import it, but just reference it from the otml file within a view entry.

Errors while loading a realObject

Q. I'm trying to load in a real Object and I get the following error Can't find a controller for this otObject: ....
A. The controller needs to be properly registered. Follow the instructions here: Registering a Controller If you are having trouble with the packages, you can set the system property: otrunk.trace.packages=true

OTrunk Scripting

Q. I followed all the steps for creating an otml file with a script on it (JavaScript), but I'm getting a bunch of errors when I try to run it. Here are some of the errors I've gotten:

Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/apache/bsf/BSFManager
Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory at org.apache.bsf.BSFManager.<init>
org.apache.bsf.BSFManager loadScriptingEngine SEVERE: Exception: java.lang.NoClassDefFoundError: org/mozilla/javascript/Scriptable
unable to load language: javascript-db: java.lang.NoClassDefFoundError: org/mozilla/javascript/Scriptable
java.lang.RuntimeException: org.apache.bsf.BSFException: unable to load language: javascript-db

A. You need to add the necessary jar files for the JavaScript engine. The jar files are located in the thirdparty project in cvs. For JavaScript, the files needed are: bsf-2.4.0.jar, js-1.6R5.jar and commons-logging.jar. Add these to your classpath and it should solve the problem.

Document generated by Confluence on Jan 27, 2014 16:52